package com.appkubes.fintech.restful.application.rent.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.appkubes.fintech.common.plan.BillDetailVo;
import com.appkubes.fintech.common.plan.BillInfoVo;
import com.appkubes.fintech.common.plan.BillPlaneUtile;
import com.appkubes.fintech.common.response.Response;
import com.appkubes.fintech.core.po.*;
import com.appkubes.fintech.core.pojo.FintechRentBillHeaderMapper;
import com.appkubes.fintech.core.pojo.FintechRentBillLinesMapper;
import com.appkubes.fintech.core.pojo.FintechRentOrderMapper;
import com.appkubes.fintech.restful.application.rent.dao.RentOrderDao;
import com.appkubes.fintech.restful.application.rent.enums.RentBillEnums;
import com.appkubes.fintech.restful.application.rent.reponse.BillDetailResponse;
import com.appkubes.fintech.restful.application.rent.reponse.BillResponse;
import com.appkubes.fintech.restful.application.rent.service.IRentBillService;
import com.appkubes.fintech.restful.application.rent.service.IRentOrderService;
import com.appkubes.fintech.restful.util.MathUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: xqc
 * @date: 2020/1/2 15:46
 * @params:
 * @return:
 */
@Service
@Slf4j
public class RentBillServiceImpl implements IRentBillService {

    @Value("${rent.bill.fine.rate}")
    private BigDecimal fineRate;
    @Resource
    private FintechRentBillHeaderMapper billHeaderMapper;
    @Resource
    private FintechRentBillLinesMapper linesMapper;
    @Resource
    private RentOrderDao rentOrderMapper;
    @Resource
    private IRentOrderService rentOrderService;

    @Override
    public Response<List<BillResponse>> queryBillInfo(String userKey) {
        List<FintechRentBillHeader> billHeaderList = getBillByUserKey(userKey);
        if (billHeaderList == null || billHeaderList.size() <= 0) {
            billHeaderList = rentOrderService.getByUserKey(userKey);  // 查还款完毕，未买断的订单。
            if (billHeaderList == null || billHeaderList.size() <= 0) {
                return Response.fail("账单不存在");
            }
        } else {
            List<FintechRentBillHeader> billHeaderNewList = rentOrderService.getByUserKey(userKey);
            if (billHeaderNewList != null && billHeaderNewList.size() > 0) {
                billHeaderList.addAll(billHeaderNewList);
            }
        }
        List<BillResponse> billResponseList = new ArrayList<>();
        for (FintechRentBillHeader billHeader : billHeaderList) {
            BillResponse billResponse = getBillInfo(billHeader.getBillKey()).getData();
            billResponseList.add(billResponse);
        }
        return Response.success(billResponseList);
    }

    @Override
    public Response<BillResponse> getBillInfo(String billKey) {
        BigDecimal hum = new BigDecimal(100);

        FintechRentBillHeader billHeader = billHeaderMapper.selectByPrimaryKey(billKey);
        BillResponse detailResponse = new BillResponse();
        FintechRentOrder order = rentOrderMapper.selectByPrimaryKey(billHeader.getOrderKey());
        detailResponse.setIsBuyOut(MathUtils.divTwo(order.getBuyOutAmount()));
        if (order.getBuyOutRepayAmount() == null) {
            order.setBuyOutRepayAmount(0);
        }
        detailResponse.setGoodsTitle(order.getGoodsTitle());
        detailResponse.setRentOrderNo(order.getRentOrderNo());
        detailResponse.setBillNo(billHeader.getBillNo());
        detailResponse.setIsPayFirst(billHeader.getIsPayFirst());

        detailResponse.setBillBuyAmt(MathUtils.divTwo(order.getBuyOutAmount() - order.getBuyOutRepayAmount()));
        detailResponse.setStatus(billHeader.getStatus());
        detailResponse.setBillKey(billHeader.getBillKey());
        detailResponse.setBillAmt(MathUtils.divTwo(billHeader.getBillAmount()));
        detailResponse.setBillInterestAmt(MathUtils.divTwo(billHeader.getBillInterest()));
        detailResponse.setBillTotalAmt(detailResponse.getBillAmt().add(detailResponse.getBillInterestAmt()));


        detailResponse.setSurFineAmt(MathUtils.divTwo(billHeader.getSurpFineAmount()));
        detailResponse.setSurInterestAmt(MathUtils.divTwo(billHeader.getSurpInterestAmount()));
        detailResponse.setSurAmt(MathUtils.divTwo(billHeader.getSurpAmount()));
        detailResponse.setSurTotalAmt(detailResponse.getSurAmt().add(detailResponse.getSurFineAmt()
                .add(detailResponse.getSurInterestAmt()).add(detailResponse.getBillBuyAmt())));
        detailResponse.setRepayAmt(MathUtils.divTwo(billHeader.getRepayAmount()));
        detailResponse.setRepayFineAmt(MathUtils.divTwo(billHeader.getRepayFineAmount()));
        detailResponse.setRepayInterestAmt(MathUtils.divTwo(billHeader.getRepayInterest()));
        detailResponse.setRepayTotalAmt(detailResponse.getRepayAmt().add(detailResponse.getRepayFineAmt().add(detailResponse.getRepayInterestAmt())));


        detailResponse.setPeriods(billHeader.getPeriods());
        detailResponse.setRepayDate(DateUtil.format(billHeader.getUnpayDate(), "yyyy-MM-dd"));
        detailResponse.setRepayPeriods(billHeader.getUnpayPeriods());

        detailResponse.setUnPayAmt(MathUtils.divTwo(billHeader.getUnpayAmount()));
        detailResponse.setUnPayFineAmt(MathUtils.divTwo(billHeader.getUnpayFineAmount()));
        detailResponse.setUnPayInteresetAmt(MathUtils.divTwo(billHeader.getUnpayInterestAmount()));
        detailResponse.setUnPayTotalAmt(detailResponse.getUnPayAmt().add(detailResponse.getUnPayFineAmt().add(detailResponse.getUnPayInteresetAmt())));
        detailResponse.setUnPayPeriod(billHeader.getUnpayPeriods());
        detailResponse.setUnPayLastDate(DateUtil.format(billHeader.getUnpayDate(), "yyyy-MM-dd"));
        List<FintechRentBillLines> linesList = getBillLinesByBillKey(billHeader.getBillKey());
        Integer beforePayAmt=0;
      List<BillDetailResponse> detailList = new ArrayList<>();
                   for(FintechRentBillLines e :linesList) {
                    BillDetailResponse detail = new BillDetailResponse();
                    if (e.getPeriod() <= billHeader.getUnpayPeriods()||e.getPeriodStartDate().getTime()<new Date().getTime()) {
                        beforePayAmt = beforePayAmt + e.getUnpayAmount();
                        beforePayAmt = beforePayAmt + e.getUnpayFineAmount();
                        beforePayAmt = beforePayAmt + e.getUnpayInterestAmount();
                    }
                    else{
                        beforePayAmt = beforePayAmt + e.getUnpayAmount();
                    }
                    detail.setStartDate(DateUtil.format(e.getPeriodStartDate(), "yyyy-MM-dd"));
                    detail.setRepayDate(DateUtil.format(e.getPeriodEndDate(), "yyyy-MM-dd"));
                    detail.setPeriods(e.getPeriod());
                    detail.setPayAmt(MathUtils.divTwo(e.getPeriodAmount()));
                    detail.setPayInterestAmt(MathUtils.divTwo(e.getPeriodInterestAmount()));
                    detail.setPayFineAmt(MathUtils.divTwo(e.getPeriodInterestAmount()));
                    detail.setPayTotalAmt(detail.getPayAmt().add(detail.getPayInterestAmt().add(detail.getPayFineAmt())));

                    detail.setSurAmt(MathUtils.divTwo(e.getUnpayAmount()));
                    detail.setSurFineAmt(MathUtils.divTwo(e.getUnpayFineAmount()));
                    detail.setSurInterestAmt(MathUtils.divTwo(e.getUnpayInterestAmount()));
                    detail.setSurTotalAmt(detail.getSurAmt().add(detail.getSurFineAmt()).add(detail.getSurInterestAmt()));

                    detail.setRepayAmt(MathUtils.divTwo(e.getRepayAmount()));
                    detail.setRepayFineAmt(MathUtils.divTwo(e.getRepayFineAmount()));
                    detail.setRepayInterestAmt(MathUtils.divTwo(e.getRepayInterestAmount()));
                    detail.setRepayTotalAmt(detail.getRepayAmt().add(detail.getRepayFineAmt()).add(detail.getRepayInterestAmt()));


                    detail.setFineAmt(MathUtils.divTwo(e.getUnpayFineAmount()));
                    detail.setStatus(e.getStatus());
                    detail.setPayAmt(MathUtils.divTwo(e.getPeriodAmount()));
                    detail.setOverDueDays(e.getOverdueDays());
                    detail.setLineKey(e.getBillLineKey());
                    detailList.add(detail);
                }
        detailResponse.setDetailList(detailList);
                   beforePayAmt=beforePayAmt+order.getBuyOutAmount();
        detailResponse.setBeforePayAmt(MathUtils.divTwo(beforePayAmt));
        return Response.success(detailResponse);
    }

    /**
     * @description: 创建租售订单
     * @author: xqc
     * @date: 2020/1/2 17:27
     * @params:
     * @return:
     */
    @Override
    public Response<FintechRentBillHeader> createBill(FintechRentOrder order, Integer isPayFirst) {
        log.info("createBill: UserKey:" + order.getUserKey() + ", OrderKey:" + order.getOrderKey());
        BillInfoVo billInfoVo = BillPlaneUtile.planBill(order.getPeriodType(), order.getPeriods()
                , order.getPeriodDays(), order.getRentAmount() / 100, order.getInterestRate()); //按照元计算
        if (isPayFirst != 0) { //上付
            List<BillDetailVo> detailVos = billInfoVo.getDetailVoList();
            Date startDate = new Date();
            for (int i = 0; i < detailVos.size(); i++) {
                BillDetailVo vo = detailVos.get(i);
                if (i == 0) {
                    vo.setStartDate(DateUtil.format(startDate, "yyyy-MM-dd"));
                    vo.setEndDate(DateUtil.format(startDate, "yyyy-MM-dd"));
                } else {
                    vo.setStartDate(DateUtil.format(startDate, "yyyy-MM-dd"));
                    vo.setEndDate(DateUtil.format(DateUtils.addWeeks(startDate, 1), "yyyy-MM-dd"));
                }
                startDate = DateUtil.parse(vo.getEndDate(), "yyyy-MM-dd");
            }
        }
        FintechRentBillHeader header = saveBillHeader(order, billInfoVo, isPayFirst);
        saveBillLines(header, billInfoVo);
        return Response.success(header);
    }

    @Override
    public FintechRentBillHeader selectByBillKey(String billKey) {
        return billHeaderMapper.selectByPrimaryKey(billKey);
    }

    @Override
    public List<FintechRentBillHeader> getBillByUserKey(String userKey) {
        FintechRentBillHeaderExample example = new FintechRentBillHeaderExample();
        FintechRentBillHeaderExample.Criteria criteria = example.createCriteria();
        criteria.andUserKeyEqualTo(userKey);
        List list = new ArrayList();
        list.add(RentBillEnums.还款中.getValue());
        list.add(RentBillEnums.未开始.getValue());
        list.add(RentBillEnums.已逾期.getValue());
        criteria.andStatusIn(list);
        example.setOrderByClause(" create_time desc ");
        List<FintechRentBillHeader> billHeadersList = billHeaderMapper.selectByExample(example);
        return billHeadersList.size() > 0 ? billHeadersList : null;
    }

    @Override
    public List<FintechRentBillLines> getBillLinesByBillKey(String billKey) {
        FintechRentBillLinesExample example = new FintechRentBillLinesExample();
        example.createCriteria().andBillKeyEqualTo(billKey);
        example.setOrderByClause(" period ");
        List<FintechRentBillLines> billHeadersList = linesMapper.selectByExample(example);
        return billHeadersList;
    }

    private FintechRentBillHeader saveBillHeader(FintechRentOrder order, BillInfoVo billInfoVo, Integer isPayFirst) {
        FintechRentBillHeader billHeader = new FintechRentBillHeader();
        BeanUtils.copyProperties(order, billHeader);
        billHeader.setOrderKey(order.getRentOrderKey());
        billHeader.setBreaksAmount(0);
        billHeader.setBillFine(0);
        billHeader.setBillAmount(order.getRentAmount()); //租售基恩
        billHeader.setBillInterest(billInfoVo.getInterestAmt() * 100);
        billHeader.setInterestRate(order.getInterestRate());
        billHeader.setSurpInterestAmount(billInfoVo.getInterestAmt() * 100);
        billHeader.setRepayInterest(0);
        billHeader.setBillNo("B" + DateUtil.format(new Date(), "yyMMddHHmmss") + RandomUtil.randomNumbers(3));
        billHeader.setPeriods(order.getPeriods());
        billHeader.setPeriodsDays(order.getPeriodDays());
        billHeader.setPeriodsType(order.getPeriodType());
        billHeader.setBillKey(UUID.randomUUID().toString().replaceAll("-", ""));
        billHeader.setCreateTime(new Date());
        billHeader.setSurpFineAmount(0);
        billHeader.setRepayAmount(0);
        billHeader.setUnpayAmount(billInfoVo.getDetailVoList().get(0).getPayAmt() * 100);
        billHeader.setUnpayPeriods(1);
        billHeader.setUnpayDate(DateUtil.parse(billInfoVo.getDetailVoList().get(0).getEndDate(), "yyyy-MM-dd"));
        billHeader.setSurpAmount(billHeader.getBillAmount());
        billHeader.setUnpayFineAmount(0);
        billHeader.setStatus(RentBillEnums.还款中.getValue());
        billHeader.setRentEndDate(DateUtil.parse(billInfoVo.getEndDate(), "yyyy-MM-dd"));
        billHeader.setRentStartDate(DateUtil.parse(billInfoVo.getStartDate(), "yyyy-MM-dd"));
        billHeader.setUnpayInterestAmount(billInfoVo.getDetailVoList().get(0).getPayInterestAmt() * 100);
        billHeader.setRepayFineAmount(0);
        billHeader.setRepayChangeAmount(0);// 多余的零头钱
        billHeader.setFineRate(fineRate.divide(new BigDecimal(100)));
        billHeader.setIsPayFirst(isPayFirst);
        billHeaderMapper.insert(billHeader);
        return billHeader;
    }

    private List<FintechRentBillLines> saveBillLines(FintechRentBillHeader header, BillInfoVo vo) {
        List<FintechRentBillLines> list = vo.getDetailVoList().stream().map(e -> {
            FintechRentBillLines line = new FintechRentBillLines();
            line.setBillKey(header.getBillKey());
            line.setBillLineKey(UUID.randomUUID().toString().replaceAll("-", ""));
            line.setBreaksAmount(0);
            line.setCreateTime(new Date());
            line.setFineRate(header.getFineRate());
            line.setOverdueDays(0);
            line.setPeriodFineAmount(0);
            line.setPayTime(null);
            line.setPeriodInterestAmount(e.getPayInterestAmt() * 100);
            line.setInterestRate(header.getInterestRate());
            line.setPeriod(e.getPeriod());
            line.setPeriodAmount(e.getPayAmt() * 100);
            line.setPeriodEndDate(DateUtil.parse(e.getEndDate(), "yyyy-MM-dd"));
            line.setPeriodStartDate(DateUtil.parse(e.getStartDate(), "yyyy-MM-dd"));
            line.setUnpayAmount(e.getPayAmt() * 100);
            line.setUnpayInterestAmount(e.getPayInterestAmt() * 100);
            line.setUnpayFineAmount(0);
            line.setRepayAmount(0);
            line.setRepayFineAmount(0);
            line.setRepayInterestAmount(0);
            line.setUpdateTime(new Date());
            //todo 加一个标志位，告知已付租金
            if (Objects.equals(e.getPeriod(), 1)) {
                line.setStatus(RentBillEnums.还款中.getValue());
//                if(flag){
//                    line.setStatus(RentBillEnums.已提还.getValue());
//                }
            } else {
                line.setStatus(RentBillEnums.未开始.getValue());
            }
            line.setIsPayFirst(header.getIsPayFirst());
            linesMapper.insert(line);
            return line;
        }).collect(Collectors.toList());
        return list;
    }

    @Override
    public FintechRentBillLines nextLines(String billKey, Integer period) {
        FintechRentBillLinesExample example = new FintechRentBillLinesExample();
        FintechRentBillLinesExample.Criteria criteria = example.createCriteria();
        criteria.andPeriodEqualTo(period + 1);
        criteria.andBillKeyEqualTo(billKey);
        List<FintechRentBillLines> list = linesMapper.selectByExample(example);
        return list.size() > 0 ? list.get(0) : null;
    }


    @Override
    public FintechRentBillLines updatePayNextLines(FintechRentBillLines lines, FintechRentBillHeader header) {
        FintechRentBillLines billLines = nextLines(lines.getBillKey(), lines.getPeriod());

        if (billLines == null) {
            return null;
        }
        if(Objects.equals(billLines.getStatus(),RentBillEnums.已提还.getValue())||
                Objects.equals(billLines.getStatus(),RentBillEnums.还款完毕.getValue())||
                Objects.equals(billLines.getStatus(),RentBillEnums.逾期完成.getValue())
        ){
            return updatePayNextLines(billLines,header); // 如果还款完毕 则继续轮换
        }

        billLines.setUpdateTime(new Date());
        if(Objects.equals(RentBillEnums.未开始.getValue(),billLines.getStatus())){
            billLines.setStatus(RentBillEnums.还款中.getValue());
        }
        linesMapper.updateByPrimaryKey(billLines);
        header.setUnpayAmount(billLines.getUnpayAmount());
        header.setUnpayFineAmount(billLines.getUnpayFineAmount());
        header.setUnpayPeriods(billLines.getPeriod());
        header.setUnpayDate(billLines.getPeriodEndDate());
        header.setUpdateTime(new Date());
        header.setUnpayInterestAmount(billLines.getPeriodInterestAmount());
        billHeaderMapper.updateByPrimaryKey(header);
        return billLines;
    }
}
